home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / program / 515 / rcs5ap1s.lzh / SYSTEM.C < prev    next >
C/C++ Source or Header  |  1991-01-30  |  4KB  |  206 lines

  1. /*
  2.  * system(): execute a command, passed as a string
  3.  *
  4.  * Written by Eric R. Smith and placed in the public domain.
  5.  *
  6.  * Modified by Allan Pratt to call _unx2dos on redirect file names
  7.  * and to call spawnvp() without calling fork() -- why bother?
  8.  *
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <stdlib.h>
  15. #include <process.h>
  16. #include <errno.h>
  17. #include <file.h>
  18. #include <osbind.h>
  19.  
  20. #ifdef DEBUG
  21. #define MSG(x) Cconws(x "\r\n")
  22. #define MSG2(x,y) printf(x,y);
  23. #else
  24. #define MSG(x)
  25. #define MSG2(x,y)
  26. #endif
  27.  
  28. #define isquote(c) ((c) == '\"' || (c) == '\'' || (c) == '`')
  29. #define ARG_ERR       ( (Argentry *) -1 )
  30.  
  31. /* struct. used to build a list of arguments for the command */
  32.  
  33. typedef struct argentry {
  34.     struct argentry *next;
  35.     char    string[1];
  36. } Argentry;
  37.  
  38.  
  39. /* allocate an Argentry that will hold the string "s" */
  40.  
  41. static Argentry *_argalloc(s)
  42.     const char *s;
  43. {
  44.     Argentry *x;
  45.  
  46.     x = (Argentry *) malloc((size_t)(sizeof(Argentry) + strlen(s) + 1));
  47.     if (!x)
  48.         return ARG_ERR;
  49.     x->next = (Argentry *) 0;
  50.     strcpy(x->string, s);
  51.     return x;
  52. }
  53.  
  54. /* free a list of Argentries */
  55.  
  56. static void _argfree(p)
  57.     Argentry *p;
  58. {
  59.     Argentry *oldp;
  60.  
  61.     while (p) {
  62.         oldp = p;
  63.         p = p->next;
  64.         free(oldp);
  65.     }
  66. }
  67.  
  68. /* parse a string into a list of Argentries. Words are defined to be
  69.  * (1) any sequence of non-blank characters
  70.  * (2) any sequence of characters starting with a ', ", or ` and ending
  71.  *     with the same character. These quotes are stripped off.
  72.  * (3) any spaces after an unquoted > or < are skipped, so
  73.  *     "ls > junk" is parsed as 'ls' '>junk'.
  74.  */
  75.  
  76. static Argentry *_parseargs(s)
  77.     const char *s;
  78. {
  79.     Argentry *cur, *res;
  80.     char buf[FILENAME_MAX];
  81.     char *t, quote;
  82.  
  83.     res = cur = _argalloc("");
  84.  
  85.     for(;;) {
  86.         t = buf;
  87. again:
  88.         while (isspace(*s)) s++;
  89.         if (!*s) break;
  90.         if (isquote(*s)) {
  91.             quote = *s++;
  92.             while (*s && *s != quote)
  93.                 *t++ = *s++;
  94.             if (*s) s++;    /* skip final quote */
  95.         }
  96.         else {
  97.             while (*s && !isspace(*s))
  98.                 *t++ = *s++;
  99.             if (*s && ( *(s-1) == '>' || *(s-1) == '<' ))
  100.                 goto again;
  101.         }
  102.         *t = 0;
  103.         cur->next = _argalloc(buf);
  104.         if (!(cur = cur->next))      /* couldn't alloc() */
  105.             return ARG_ERR;
  106.     }
  107.     cur->next = (Argentry *) 0;
  108.     cur = res; res = res->next; free(cur);
  109.     return res;
  110. }
  111.  
  112.  
  113. /* Here is system() itself.
  114.  * FIXME: we probably should do I/O redirection and wildcard expansion.
  115.  * also, should errno get set here??
  116.  */
  117.  
  118. static int retval;
  119.  
  120. int system(s)
  121.     const char *s;
  122. {
  123.     Argentry *al, *cur;
  124.     char **argv, *p;
  125.     int  argc, i;
  126.     char *infile, *outfile;
  127.     int  infd, outfd, append = 0;
  128.     int oldin, oldout;    /* hold the Fdup'd in, out */
  129.     char path[FILENAME_MAX];
  130.  
  131.     if (!s)        /* check for system() supported ?? */
  132.         return 1;
  133.     al = _parseargs(s);        /* get a list of args */
  134.     if (al == ARG_ERR)        /* not enough memory */
  135.         return (errno = ENOMEM);
  136.  
  137.     infile = outfile = "";
  138. MSG("in system");
  139.  
  140. /* convert the list returned by _parseargs to the normal char *argv[] */
  141.     argc = i = 0;
  142.     for (cur = al; cur; cur = cur->next)
  143.         argc++;
  144.     if (!(argv = (char **) malloc((size_t)(argc * sizeof(char *)))))
  145.         return (errno = ENOMEM);
  146.     for (cur = al; cur; cur = cur->next) {
  147.         p = cur->string;
  148.         if (*p == '>') {
  149. MSG("redirecting output");
  150.             outfile = p+1;
  151.             if (*outfile == '>') {
  152.                 outfile++;
  153.                 append = 1;
  154.             }
  155.             else
  156.             append = 0;
  157.         }
  158.         else if (*p == '<') {
  159. MSG("redirecting input");
  160.             infile = p+1;
  161.         }
  162.         else
  163.             argv[i++] = p;
  164.     }
  165.      argv[i] = (char *)0;
  166.  
  167. /* now actually run the program */
  168.     /* there was a "vfork" call here, but why bother? */
  169.     if (*infile) {
  170.         _unx2dos(infile,path);
  171.         infd = Fopen(path, 0);
  172.         if (infd < __SMALLEST_VALID_HANDLE) {
  173.             perror(infile);
  174.             _exit(2);
  175.         }
  176.         oldin = Fdup(0);
  177.         Fforce(0, infd);
  178.     }
  179.     if (*outfile) {
  180.         _unx2dos(outfile,path);
  181.         if (append) {
  182.             outfd = Fopen(path, 2);
  183.             if (outfd < __SMALLEST_VALID_HANDLE)
  184.                 outfd = Fcreate(path, 0);
  185.             else
  186.                 Fseek(0L, outfd, 2);
  187.         }
  188.         else
  189.             outfd = Fcreate(path, 0);
  190.         if (outfd < __SMALLEST_VALID_HANDLE) {
  191.             perror(outfile);
  192.             _exit(2);
  193.         }
  194.         oldout = Fdup(1);
  195.         Fforce(1, outfd);
  196.     }
  197. MSG("Calling spawnvp");
  198.     retval = spawnvp(P_WAIT, argv[0], argv);
  199. MSG("Exiting");
  200.     if (*infile) Fforce(0,oldin), Fclose(oldin), Fclose(infd);
  201.     if (*outfile) Fforce(1,oldout), Fclose(oldout), Fclose(outfd);
  202.     free(argv);
  203.     _argfree(al);
  204.     return retval;
  205. }
  206.